package com.codeos.khttp.request;

import com.codeos.khttp.KHttpListener;
import com.codeos.khttp.KUrl;
import com.codeos.khttp.request.body.KHttpBody;
import com.codeos.khttp.utils.KHttpUtils;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

public class KRequest {

//    private KHttpListener mListener;
    private String mHttpProtocalVer = "HTTP/1.1";
    private String mHttpEnd = KHttpUtils.gHttpEnd;

    private String mHttpMethod = "GET";
    private KUrl mUrl;
    private Map<String, String> mHeaderMap;
    private Map<String, String> mCookieMap;
    private KHttpBody mBody;

    private StringBuffer mHttpHeader = new StringBuffer();

    private KRequest(Builder builder) {
        mUrl = builder.getUrl();
        mHeaderMap = builder.getHeaderMap();
        mCookieMap = builder.getCookieMap();
        mBody = builder.getHttpBody();

        if(mBody != null && mBody.isBodyEmpty() == false) {
            mHttpMethod = "POST";
        }
    }

    public String getRequestIP() {
        return mUrl.getHostIP();
    }

    public int getRequestPort() {
        return mUrl.getPort();
    }

    /**
     * 将自定义Header转成字符串
     * @return
     */
    private String customHeaderToString() {
        if(mHeaderMap.size() <= 0) {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        for(String key : mHeaderMap.keySet()) {
            sb.append(key + ": " +mHeaderMap.get(key) + mHttpEnd);
        }

        return sb.toString();
    }

    /**
     * 将Cookie转成字符串
     * @return
     */
    private String cookieToString() {
        if(mCookieMap.size() <= 0) {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        sb.append("Cookie:");
        for(String key : mCookieMap.keySet()) {
            sb.append(" " + key+"="+mCookieMap.get(key));
        }
        sb.append(mHttpEnd);

        return sb.toString();
    }

    public void preRequest() {
        //------------------------------------------------------------------------------------------------------
        // Http Header start
        mHttpHeader.append(mHttpMethod + " " + mUrl.getTotalFilePath() + " " + mHttpProtocalVer +mHttpEnd);
        if(mUrl.isHostIP()) {
            mHttpHeader.append("Host: "+mUrl.getHost()+":"+mUrl.getPort()+mHttpEnd);
        } else {
            mHttpHeader.append("Host: "+mUrl.getHost()+":"+mHttpEnd);
        }
        mHttpHeader.append("cache-control: no-cache"+mHttpEnd);
        mHttpHeader.append("User-Agent: PostmanRuntime/7.6.1"+mHttpEnd);
        mHttpHeader.append("Accpet: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*"+mHttpEnd);
        mHttpHeader.append("Accept-Language: zh-cn"+mHttpEnd);
        mHttpHeader.append("accept-encoding: gzip, deflate"+mHttpEnd);

        // 自定义Header
        String customHeaders = customHeaderToString();
        if(customHeaders != null) {
            mHttpHeader.append(customHeaders);
        }
        // Cookie
        String cookies = cookieToString();
        if(cookies != null) {
            mHttpHeader.append(cookies);
        }
        // Body header
        if(mBody != null && mBody.isBodyEmpty() == false) {
            mHttpHeader.append("content-type: multipart/form-data; boundary="+mBody.getHeaderBoundary()+mHttpEnd);
            mHttpHeader.append("content-length: "+mBody.getBodyLength()+mHttpEnd);

        }
        mHttpHeader.append("Connection: keep-alive"+mHttpEnd);
        mHttpHeader.append(mHttpEnd);
    }

    private void sendHeaderData(OutputStream os, OutputStreamWriter writer) throws IOException {
        preRequest();
        writer.write(mHttpHeader.toString());
        writer.flush();
    }

    private void sendBodyData(OutputStream os, OutputStreamWriter writer) throws IOException {
        if(mBody != null && mBody.isBodyEmpty() == false) {
            mBody.sendBodyData(os, writer);
        }
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append(mHttpHeader.toString());
        if(mBody != null && mBody.isBodyEmpty() == false) {
            sb.append(mBody.toString());
        }
        return sb.toString();
    }

    public void request(OutputStream os, OutputStreamWriter writer) throws IOException {

        // url()必选
        if(mUrl == null) {
            throw new IllegalStateException("call url() to set url first!");
        }

        sendHeaderData(os, writer);
        sendBodyData(os, writer);
    }

    public static class Builder {


        private KUrl mUrl;

        // 需要自定义header
        private Map<String, String> mHeaderMap = new HashMap<String, String>();

        // Cookie
        private Map<String, String> mCookieMap = new HashMap<String, String>();

        // form表单上传
        private KHttpBody mBody;

        public KUrl getUrl() {
            return mUrl;
        }

        public Map<String, String> getHeaderMap() {
            return mHeaderMap;
        }

        public Map<String, String> getCookieMap() {
            return mCookieMap;
        }

        public KHttpBody getHttpBody() {
            return mBody;
        }

        public Builder url(String url) {
            mUrl = new KUrl(url);
            return this;
        }

        /**
         * 增加一个Header键值对
         * @param key
         * @param value
         * @return
         */
        public Builder addHeader(String key, String value) {
            mHeaderMap.put(key, value);

            return this;
        }

        /**
         * 增加一组Header键值对
         * @param headers
         * @return
         */
        public Builder addHeaders(Map<String, String> headers) {
            mHeaderMap.putAll(headers);

            return this;
        }

        /**
         * 增加一个Cookie键值对
         * @param key
         * @param value
         * @return
         */
        public Builder addCookie(String key, String value) {
            mCookieMap.put(key, value);

            return this;
        }

        /**
         * 增加一组Cookie键值对
         * @param cookies
         * @return
         */
        public Builder addCookies(Map<String, String> cookies) {
            mCookieMap.putAll(cookies);

            return this;
        }

        public Builder addPostBody(KHttpBody body) {

            mBody = body;

            return this;
        }

        public KRequest build() {
            return new KRequest(this);
        }
    }
}
